﻿Shader "SuperCloud"
{
    Properties
    {
        [HDR]_ColorTint("色调", Color) = (1,1,1,1)
        [HDR]_AddColor("附加色调", Color) = (1,1,1,1)
        _AddRange("颜色范围", Range(-1, 1)) = -1
        _ScaleAndMove("缩放与移动", Vector) = (1,1,1,1)
        _Soft("接触点软边", Range(0, 1)) = 0.5
        _Edge("接触点边缘", Range(0, 0.9)) = 0.5
        _SoftEdge("边缘软边", Range(0, 0.9)) = 0.5
        _Depth("深度", Float) = 0
        [NoScaleOffset]_Control("消散", 2D) = "white" {}  
    }

    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Opaque" }

        Pass
        {
			Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct app_data
            {
                half4 positionOS : POSITION;
                half3 normalOS : NORMAL;
                half4 tangentOS : TANGENT;
                half4 texcoord0 : TEXCOORD0;
            };

            struct v2f
            { 
                half4 positionCS : SV_POSITION;       
                half3 positionWS : TEXCOORD0;
                half4 uv0 : TEXCOORD1;
                half4 proj : TEXCOORD2;
            };

            half4 _ColorTint;
            half4 _ScaleAndMove;
            half _Soft;
            half _Edge;
            half _SoftEdge;
            sampler2D _Control;

            half _Parallax;
            half _Accuracy;
            half _HeightAmount;

            half4 _AddColor;
            half _AddRange;

            half _Depth;

            sampler2D _CameraDepthTexture;

			v2f vert(app_data IN)
            {
                v2f o = (v2f)0;

                // 将顶点坐标从模型空间变换的世界空间
                half3 positionWS = mul(unity_ObjectToWorld, IN.positionOS);
                o.positionWS = positionWS;

                // 计算纹理采样时使用的UV
                o.uv0.xy = IN.texcoord0.xy;
                o.uv0.zw = IN.texcoord0.zw;

                // 将顶点坐标从世界空间变换到齐次裁剪空间
                o.positionCS = UnityObjectToClipPos(IN.positionOS);
                o.proj = ComputeScreenPos(o.positionCS); 
                
                return o;
            }

            inline float Unity_SimpleNoise_RandomValue_float(float2 uv)
            {
                return frac(sin(dot(uv, float2(12.9898, 78.233))));
            }

            inline float Unity_SimpleNnoise_Interpolate_float(float a, float b, float t)
            {
                return (1.0 - t) * a + (t * b);
            }

            inline float Unity_SimpleNoise_ValueNoise_float(float2 uv)
            {
                float2 i = floor(uv);
                float2 f = frac(uv);
                f = f * f * (3.0 - 2.0 * f);

                uv = abs(frac(uv) - 0.5);
                float2 c0 = i + float2(0.0, 0.0);
                float2 c1 = i + float2(1.0, 0.0);
                float2 c2 = i + float2(0.0, 1.0);
                float2 c3 = i + float2(1.0, 1.0);
                float r0 = Unity_SimpleNoise_RandomValue_float(c0);
                float r1 = Unity_SimpleNoise_RandomValue_float(c1);
                float r2 = Unity_SimpleNoise_RandomValue_float(c2);
                float r3 = Unity_SimpleNoise_RandomValue_float(c3);

                float bottomOfGrid = Unity_SimpleNnoise_Interpolate_float(r0, r1, f.x);
                float topOfGrid = Unity_SimpleNnoise_Interpolate_float(r2, r3, f.x);
                float t = Unity_SimpleNnoise_Interpolate_float(bottomOfGrid, topOfGrid, f.y);
                return t;
            }

            float Unity_SimpleNoise_float(float2 UV)
            {
                float t = 0.0;

                float freq = pow(2.0, float(0));
                float amp = pow(0.5, float(3 - 0));
                t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x / freq, UV.y / freq)) * amp;

                freq = pow(2.0, float(1));
                amp = pow(0.5, float(3 - 1));
                t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x / freq, UV.y / freq)) * amp;

                freq = pow(2.0, float(2));
                amp = pow(0.5, float(3 - 2));
                t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x / freq, UV.y / freq)) * amp;

                return t;
            }

            float NoiseParallax(half2 uv)
            {
                return Unity_SimpleNoise_float(uv);
            }

            // 使用SV_Target，用来标记把渲染结果存入RT0
            half4 frag(v2f IN) : SV_Target
            {
                half2 mainUV1 = IN.positionWS.xz * _ScaleAndMove.xy;
                half2 mainUV2 = IN.positionWS.xy * _ScaleAndMove.xy;
                half2 mainUV3 = IN.positionWS.zy * _ScaleAndMove.xy;

                // 附加颜色
                half4 addColor = _AddColor;
                half height = (1 - NoiseParallax(mainUV1) * NoiseParallax(mainUV2) * NoiseParallax(mainUV3));
                height = smoothstep(-_Depth, 1 + _Depth, height);
                height = saturate(height + _AddRange);

                half4 baseColor = _ColorTint;
                baseColor.rgb = lerp(baseColor.rgb, addColor.rgb, height);

                float2 depthUV = IN.proj.xy / IN.proj.w;

                half depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, depthUV);
                depth = LinearEyeDepth(depth);

                half4 ControlColor = tex2D(_Control, IN.uv0.xy);
  
                half deltaDepth = depth - IN.proj.w;
                baseColor.a = saturate(deltaDepth * _Soft * (1 - height) - (1 - ControlColor.r));
                baseColor.a = smoothstep(_Edge, 1, baseColor.a);

                baseColor.a *= smoothstep(0, _SoftEdge, IN.uv0.y);
                baseColor.a *= smoothstep(0, _SoftEdge, 1 - IN.uv0.y);
                baseColor.a *= smoothstep(0, _SoftEdge, IN.uv0.x);
                baseColor.a *= smoothstep(0, _SoftEdge, 1 - IN.uv0.x);

                baseColor.a *= lerp(_ColorTint.a, _AddColor.a, height);

                return baseColor;
            }
            ENDCG
        }
    }
}